#   This file is part of emesene.
#
#    Eval plugin is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    Eval plugin is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with emesene; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

#h4x0r3d by C10uD <c10ud.dev@gmail.com>
#heavy fixes by jandem <jandemooij@gmail.com>
#special thanks to teh internets

VERSION = '0.42'

import math
import pango
import pygtk
import gtk
from gtk import gdk
import cairo
from Parser import UserListDataType
import Plugin

supports_alpha = False

def screen_changed(widget, old_screen=None):
     
    global supports_alpha
    screen = widget.get_screen()
    colormap = screen.get_rgba_colormap()
    if colormap == None:
        print 'Your screen does not support alpha channels!'
        colormap = screen.get_rgb_colormap()
        supports_alpha = False
    else:
        print 'Your screen supports alpha channels!'
        supports_alpha = True
    
    widget.set_colormap(colormap)

class AlphaOSD(gtk.Window):
    def __init__(self, dimensions, xy_coords, colors, font, fontcolor):
        
        gtk.Window.__init__(self)
        self.set_border_width(10)
        wi, he = dimensions
        self.set_default_size(wi, he)
        x, y = xy_coords
        self.move(x, y)
        self.set_title(_('emesene OSD'))
        self.set_app_paintable(True)
    
        self.width, self.height = dimensions
        self.colors = colors

        self.font = font   
        self.fontcolor = fontcolor     
        self.lab = gtk.Label('<span font_desc="' + self.font + '" ' +\
            'foreground="' + self.fontcolor + '">' +\
            _("emesene OSD - welcome") + '</span>')
        self.lab.set_use_markup(True)
        self.lab.set_alignment(0, 0)
        self.lab.set_ellipsize(pango.ELLIPSIZE_END)
        #i am too l33t
        #<dxdx> NO U
        self.line_width, self.line_height = self.lab.get_layout().get_size()
        self.line_height = pango.PIXELS(self.line_height)
        
        self.vbox = gtk.VBox(False, 5)
        self.vbox.pack_start(self.lab, False, False, 0)

        self.add(self.vbox)
        self.connect('expose-event', self.expose)
        self.connect('screen-changed', screen_changed)
        
        self.set_decorated(False)
        self.add_events(gdk.BUTTON_PRESS_MASK)
        self.add_events(gdk._2BUTTON_PRESS)
        self.connect("button-press-event", self.on_button_press)
    
        screen_changed(self)
        self.L = []
        
        self.set_keep_above(True)
        self.stick() # show in all workspaces
        self.set_property('skip-taskbar-hint', True)
        
        self.show_all()
  
    def on_button_press(self, widget, event):
        if event.type == gdk._2BUTTON_PRESS and event.button == 1:
            widget.set_decorated(not widget.get_decorated())
    
        #clear widget buffer on right click
        elif event.button == 3: 
            del self.L[:]
            self.lab.set_markup('<span font_desc="' + self.font + '" ' +\
            'foreground="' + self.fontcolor + '">' +\
            _("emesene OSD - welcome") + '</span>')
            
    #This is called when we need to draw the windows contents
    
    def expose(self, widget, event):
        global supports_alpha

        cr = widget.window.cairo_create()
      
        if supports_alpha == True:
            cr.set_source_rgba(1.0, 1.0, 1.0, 0.0) # Transparent
        else:
            cr.set_source_rgb(1.0, 1.0, 1.0) # Opaque white
        
        padding = 5
        #increase the first value to get moar roundness!!
        rounded = (20 / 100.0) * min(self.width, self.height) / 2 \
            - padding
        # Draw the background
        cr.set_operator(cairo.OPERATOR_SOURCE)
        cr.paint()
        
        #draw a nice rounded rectangle
        w, h = [float(size) for size in widget.get_size()]
        
        # 1 : 65535 = x : color(alpha)
        red, green, blue, falpha = [float(color) / 65535 
            for color in self.colors]

        cr.set_source_rgba(red, green, blue, falpha)
        cr.move_to(0+padding+rounded, 0+padding)
        cr.line_to(w-padding-rounded, 0+padding)
        cr.arc(w-padding-rounded, 0+padding+rounded, rounded, math.pi/2, 0)
        cr.line_to(w-padding, h-padding-rounded)
        cr.arc(w-padding-rounded, h-padding-rounded, rounded, 0, math.pi/2)
        cr.line_to(0+padding+rounded, h-padding)
        cr.arc(0+padding+rounded, h-padding-rounded, rounded, \
            math.pi+math.pi/2, math.pi)
        cr.line_to(0+padding, 0+padding+rounded)
        cr.arc(0+padding+rounded, 0+padding+rounded, rounded, math.pi/2, 0)
        
        cr.fill()
        cr.stroke()    

        children = self.get_children()
        for c in children:
            self.propagate_expose(c, event)

    def add_some_damn_message(self, text):
        self.width, self.height = self.get_size()
        self.max_lines = self.height / self.line_height -1
        
        #adds a new msg to our nice list
        for line in text.split("\n"):
            self.L.append(line) 
            if len(self.L) >= self.max_lines:
                self.L.pop(0)
                
        #we can fill buffer now, hell yeah!
        myBuf = '<span font_desc="' + self.font + '" ' +\
            'foreground="' + self.fontcolor + '">' + '\n'.join(self.L) + \
            '</span>'
         
        self.lab.set_label(myBuf.rstrip("n"))
        
        
class MainClass(Plugin.Plugin):

    def __init__(self, controller, msn):
        Plugin.Plugin.__init__(self, controller, msn)

        self.description = _('emesene on-screen-display for viewing'
                             ' incoming messages')
        self.authors = {'C10uD': 'c10ud.dev@gmail.com'}
        self.website = 'http://emesene.org'
        self.displayName = _('OSD')
        self.name = 'OSD'
        self.enabled = False
        self.osd = None 
        self.config = controller.config
        self.controller = controller

        self._row = 0
        
    def start(self):
        self.enabled = True

        self.config.readPluginConfig(self.name)
        self.colors = [ \
            int(self.config.getPluginValue( self.name, 'colorR', '0' )), \
            int(self.config.getPluginValue( self.name, 'colorG', '0' )), \
            int(self.config.getPluginValue( self.name, 'colorB', '0' )), \
            int(self.config.getPluginValue( self.name, 'colorA', '32000' ))]
        self.dimensions = [ \
            int(self.config.getPluginValue( self.name, 'width', '800' )), \
            int(self.config.getPluginValue( self.name, 'height', '200' ))]
        self.coords = [ \
            int(self.config.getPluginValue( self.name, 'x', '800' )), \
            int(self.config.getPluginValue( self.name, 'y', '200' ))]
        self.font = self.config.getPluginValue( \
            self.name, 'font', 'Monospace Italic 14')
        self.fontcolor = [ \
            int(self.config.getPluginValue( self.name, 'fontR', '0' )), \
            int(self.config.getPluginValue( self.name, 'fontG', '0' )), \
            int(self.config.getPluginValue( self.name, 'fontB', '0' ))]
        # from [R, G, B] to #RRRRGGGGBBBB (string)
        self.Hfontcolor = '#'+ self.int_to_hex(self.fontcolor[0]) + \
            self.int_to_hex(self.fontcolor[1]) + \
            self.int_to_hex(self.fontcolor[2])
        self.maxNickLength = \
            int(self.config.getPluginValue( self.name, 'maxNick', '0' ))
        
        #construct the osd main window
        self.osd = AlphaOSD(self.dimensions, self.coords, \
            self.colors, self.font, self.Hfontcolor)
        #connect to new received message signal
        self.newMsgId = self.controller.conversationManager.connect(
            'receive-message', self.newMsg )

    #returns a 4-digit string of hexadecimal value
    def int_to_hex(self, number):  
        myHex = str(hex(number)[2:])
        while (len(myHex) < 4):
            myHex = '0' + myHex
        return myHex
        
    def stop(self):
        width, height = self.osd.get_size()
        self.config.setPluginValue( self.name, 'width', width )
        self.config.setPluginValue( self.name, 'height', height )
        x, y = self.osd.get_position()
        self.config.setPluginValue( self.name, 'x', x )
        self.config.setPluginValue( self.name, 'y', y )

        self.enabled = False
        self.controller.conversationManager.disconnect( self.newMsgId )
        self.osd.destroy()
        self.osd = None

    def check(self):
        return (True, 'Ok')
 
    def configure( self ):
               
        self.confW = Plugin.ConfigWindow(_('emesene OSD config'), '')

        tnable = gtk.Table(2)
        self._row = 0

        def addrow(text, bnutton):
            row = self._row
            lnabel = gtk.Label(text)
            lnabel.set_alignment(0, 1)
            tnable.attach(lnabel, 0, 1, row, row + 1)
            tnable.attach(bnutton, 1, 2, row, row + 1)
            self._row += 1

        #bg colour chooser
        colorbutton = gtk.ColorButton( gtk.gdk.Color(self.colors[0], 
            self.colors[1], self.colors[2]) )
        colorbutton.set_use_alpha(True)
        colorbutton.set_alpha(self.colors[3])
        colorbutton.set_title(_('Select a Color'))
        addrow(_('Background Color:'), colorbutton)
        
        #Font chooser
        fontbutton = gtk.FontButton(self.font)
        fontbutton.set_use_font(True)
        fontbutton.set_title('Select a font')
        addrow(_('Current Font:'), fontbutton)
        
        #Font Color Chooser
        fontcolor = gtk.ColorButton(gtk.gdk.Color(self.fontcolor[0], 
            self.fontcolor[1], self.fontcolor[2]))
        fontcolor.set_use_alpha(False)
        fontcolor.set_title(_('Select a Color'))
        addrow(_('Font Color:'), fontcolor)
        
        #Maximum nickname length
        inputMaxLength = gtk.Entry(2)
        inputMaxLength.set_text(str(self.maxNickLength))
        addrow(_('Max Nick Chars:'), inputMaxLength)
        
        #pack widgets together

        self.confW.vbox.pack_start(tnable)
        self.confW.show_all()
        
        r = self.confW.run()

        if r is not None:
            color = colorbutton.get_color()
            alpha = colorbutton.get_alpha()
            font = fontbutton.get_font_name()
            fontcolor = fontcolor.get_color()
            maxlength = int(inputMaxLength.get_text())

            self.colors = [color.red, color.green, color.blue, alpha]
            
            self.config.setPluginValue( self.name, 'colorR', color.red )
            self.config.setPluginValue( self.name, 'colorG', color.green )
            self.config.setPluginValue( self.name, 'colorB', color.blue )
            self.config.setPluginValue( self.name, 'colorA', alpha )
            self.config.setPluginValue( self.name, 'font', font )
            self.config.setPluginValue( self.name, 'fontR', fontcolor.red )
            self.config.setPluginValue( self.name, 'fontG', fontcolor.green )
            self.config.setPluginValue( self.name, 'fontB', fontcolor.blue )
            self.config.setPluginValue( self.name, 'maxNick', maxlength )
            #[quote] YES YOU'VE GUESSED RIGHT! THIS IS A HACK! [/quote]
            self.stop()
            self.start()

        return True

    def newMsg(self, switchboard, conversation, mail, nick, message,
               format, charset):
        '''called when someone send a message'''
        nick = self.controller.msn.contactManager.getContactNameToDisplay(mail)
        parsednick = self.controller.unifiedParser.getParser(nick).get()                                   
        if (self.maxNickLength):
            parsednick = parsednick[:self.maxNickLength]
        self.osd.add_some_damn_message(parsednick + ': ' + message)
